import React from 'react';
import PropTypes from 'prop-types';

/**
 * 关键词高亮
 * @param {string|ReactNode} text 需要匹配的文本
 * @param {string} keyword 关键词
 * @param {object} highlightStyle 高亮样式
 * @param {boolean} ignoreCase 忽略大小写
 */
const highlightText = (text, keyword, highlightStyle, ignoreCase) => {
    let keywordRegExp;
    if (text === '' || text === undefined) {
        return '';
    }
    if (!keyword || keyword.length === 0) {
        return text;
    }
    // 把字符串类型的关键字转换成正则
    if (keyword) {
        if (keyword instanceof Array) {
            keywordRegExp = new RegExp(keyword.filter(item => !!item).join('|'), ignoreCase ? 'ig' : 'g');
        } else if (typeof keyword === 'string') {
            keywordRegExp = new RegExp(keyword, ignoreCase ? 'ig' : 'g');
        }
    }
    if (text && keywordRegExp) {
        const newData = text.split(keywordRegExp); //  通过关键字的位置开始截取，结果为一个数组
        const matchWords = text.match(keywordRegExp); // 获取匹配的文本
        const len = newData.length;

        return (
            <>
                {newData.map((item, index) => (
                    // eslint-disable-next-line react/no-array-index-key
                    <React.Fragment key={index}>
                        {item}
                        {index !== len - 1 && <mark style={highlightStyle}>{matchWords[index]}</mark>}
                    </React.Fragment>
                ))}
            </>
        );
    }
    return text;
};

// 递归子组件
const highlightChildComponent = (item, keywords, highlightStyle, ignoreCase) => {
    if (typeof item === 'string') {
        return highlightText(item, keywords, highlightStyle, ignoreCase);
    }
    // children 如果是文本, item.props.children 会等于 'string'
    if (item?.props?.children && typeof item?.props?.children === 'string') {
        const newItem = { ...item };
        newItem.props = {
            ...newItem.props,
            children: highlightText(newItem.props.children, keywords, highlightStyle, ignoreCase)
        };
        return newItem;
    }
    // 如果还有其他元素, 会返回一个数组, 遍历做判断
    if (item?.props?.children && item?.props?.children instanceof Array) {
        const newItem = Object.assign({}, item);
        newItem.props = {
            ...newItem.props,
            children: item.props?.children.map((child, index) => (
                <React.Fragment key={index}>
                    {highlightChildComponent(child, keywords, highlightStyle, ignoreCase)}
                </React.Fragment>
            ))
        };
        return newItem;
    }
    return item;
};

const HighlightText = props => {
    const { keywords, highlightStyle, ignoreCase, children } = props;
    return React.Children.map(children, item => highlightChildComponent(item, keywords, highlightStyle, ignoreCase));
};

HighlightText.propTypes = {
    // 颜色列表
    keywords: PropTypes.oneOfType([PropTypes.string, PropTypes.arrayOf(PropTypes.string)]),
    // 图标源配置
    highlightStyle: PropTypes.object,
    // 忽略大小写
    ignoreCase: PropTypes.bool
};

HighlightText.defaultProps = {
    keywords: null,
    highlightStyle: { color: '#ffa22d', backgroundColor: 'transparent', padding: 0 },
    ignoreCase: true
};
HighlightText.displayName = 'HighlightText';

export default HighlightText;
